from ui.components.base.widget import TgBaseWidget
from ui.components.layouts.vbox_layout import TgVBoxLayout
from ui.components.layouts.hbox_layout import TgHBoxLayout
from ui.components.inputs.label import TgLabel
from ui.components.buttons.button import TgButton
from ui.components.composite.plot_widget import TgPlotWidget
from ui.components.inputs.date_edit import TgDateEdit
from ui.components.inputs.combo_box import TgComboBox
from ui.components.containers.scroll_area import TgScrollArea
from ui.components.charts.surface_3d_chart import TgSurface3DChart
from datetime import datetime, timedelta
from loguru import logger
from typing import Dict
from util import get_latest_trading_date
import pandas as pd


class OptionsVolatilityView(TgBaseWidget):
    
    def __init__(self):
        super().__init__()
        self.layout = TgVBoxLayout(self)
        self._setup_ui()

    def _setup_ui(self):
        # 创建滚动区域
        self.scroll_area = TgScrollArea()
        self.scroll_content = TgBaseWidget()
        self.scroll_layout = TgVBoxLayout(self.scroll_content)

        # 创建并添加第二个图表及其控件 - IV历史折线图
        self._create_iv_history_section()

        # 创建并添加第三个图表及其控件
        self._create_historical_iv_section()
        
        # 创建并添加查询控件（用于波动率锥查询）
        self._create_cone_query_section()

        # 创建并添加波动率锥图表
        self._create_cone_section()

        # 创建并添加3D波动率曲面图表
        self._create_iv_surface_3d_section()

        self.scroll_layout.addStretch(1)

        # 设置滚动区域
        self.scroll_area.setWidget(self.scroll_content)
        self.scroll_area.setWidgetResizable(True)
        self.scroll_area.set_horizontal_scroll_policy('always_off')
        
        # 确保滚动内容适应父容器宽度
        self.scroll_content.set_expanding_minimum_policy()
        self.layout.addWidget(self.scroll_area)

    def _create_cone_query_section(self):
        """创建波动率锥查询控件区域"""
        # 创建控件
        controls_layout = self._create_cone_query_controls()
        self.scroll_layout.addLayout(controls_layout)
        self.scroll_layout.addSpacing(10)

    def _create_cone_query_controls(self):
        """创建波动率锥查询控件"""
        controls_layout = TgHBoxLayout()
        controls_layout.addWidget(TgLabel("日期:"))
        self.date_input = TgDateEdit()
        controls_layout.addWidget(self.date_input)
        controls_layout.addWidget(TgLabel("标的:"))
        self.underlying_combo = TgComboBox()
        self.underlying_combo.setMinimumWidth(120)
        self.underlying_combo.setMaximumWidth(200)
        controls_layout.addWidget(self.underlying_combo)
        self.query_button = TgButton("查询波动率锥")
        controls_layout.addWidget(self.query_button)
        controls_layout.addStretch(1)
        return controls_layout

    def _create_cone_section(self):
        # 添加说明标签
        cone_explanation_label = TgLabel("每个到期日平值认购和认沽的隐含波动率。虚线是上一个交易日的隐含波动率。可对比分析当天对比前一天隐波变化情况", style_type='description')
        cone_explanation_label.setWordWrap(True)
        self.scroll_layout.addWidget(cone_explanation_label)

        # 创建图表
        self.cone_chart = TgPlotWidget(title="期权波动率锥曲线", time_axis=True)
        self.cone_chart.setFixedHeight(400)
        self.cone_chart.setMinimumWidth(300)
        self.cone_chart.set_mouse_interaction(enabled=True)
        self.scroll_layout.addWidget(self.cone_chart)
        self.scroll_layout.addSpacing(20)

    def _create_historical_iv_section(self):
        # 创建控件
        controls_layout = self._create_historical_iv_controls()
        self.scroll_layout.addLayout(controls_layout)

        # 添加说明标签
        historical_iv_explanation_label = TgLabel("每个到期日的平值合约隐含波动率历史走势", style_type='description')
        historical_iv_explanation_label.setWordWrap(True)
        self.scroll_layout.addWidget(historical_iv_explanation_label)

        # 创建图表
        self.historical_iv_chart = TgPlotWidget(title="期权平值历史隐含波动率", time_axis=True)
        self.historical_iv_chart.setFixedHeight(400)
        self.historical_iv_chart.setMinimumWidth(300)
        self.historical_iv_chart.set_mouse_interaction(enabled=True)
        self.scroll_layout.addWidget(self.historical_iv_chart)
        self.scroll_layout.addSpacing(20)

    def _create_historical_iv_controls(self):
        controls_layout = TgHBoxLayout()
        # controls_layout.addWidget(TgLabel("标的:"))
        self.historical_iv_underlying_combo = TgComboBox()
        self.historical_iv_underlying_combo.setMinimumWidth(120)
        self.historical_iv_underlying_combo.setMaximumWidth(200)
        controls_layout.addWidget(self.historical_iv_underlying_combo)
        
        # 添加期权类型下拉框
        self.historical_iv_option_class_combo = TgComboBox()
        self.historical_iv_option_class_combo.addItem("CALL", "CALL")
        self.historical_iv_option_class_combo.addItem("PUT", "PUT")
        self.historical_iv_option_class_combo.setMinimumWidth(80)
        self.historical_iv_option_class_combo.setMaximumWidth(100)
        controls_layout.addWidget(self.historical_iv_option_class_combo)
        
        # controls_layout.addWidget(TgLabel("起始日期:"))
        self.start_date_input = TgDateEdit()
        controls_layout.addWidget(self.start_date_input)
        # controls_layout.addWidget(TgLabel("结束日期:"))
        self.end_date_input = TgDateEdit()
        controls_layout.addWidget(self.end_date_input)
        self.query_historical_iv_button = TgButton("查询")
        controls_layout.addWidget(self.query_historical_iv_button)
        controls_layout.addStretch(1)
        return controls_layout

    def _create_iv_history_section(self):
        """创建IV历史查询区域"""
        # 创建控件
        controls_layout = self._create_iv_history_controls()
        self.scroll_layout.addLayout(controls_layout)

        # 添加说明标签
        iv_history_explanation_label = TgLabel("每天近月和远月认购和认沽合约隐含波动率走势", style_type='description')
        iv_history_explanation_label.setWordWrap(True)
        self.scroll_layout.addWidget(iv_history_explanation_label)

        # 创建图表
        self.iv_history_chart = TgPlotWidget(title="期权隐含波动率历史走势", time_axis=True)
        self.iv_history_chart.setFixedHeight(400)
        self.iv_history_chart.setMinimumWidth(300)
        self.iv_history_chart.set_mouse_interaction(enabled=True)
        self.scroll_layout.addWidget(self.iv_history_chart)
        self.scroll_layout.addSpacing(20)

    def _create_iv_history_controls(self):
        """创建IV历史查询控件"""
        controls_layout = TgHBoxLayout()
        
        # 标的选择
        self.iv_history_underlying_combo = TgComboBox()
        self.iv_history_underlying_combo.setMinimumWidth(120)
        self.iv_history_underlying_combo.setMaximumWidth(200)
        controls_layout.addWidget(self.iv_history_underlying_combo)
        
        # 起始日期
        self.iv_history_start_date = TgDateEdit()
        controls_layout.addWidget(self.iv_history_start_date)
        
        # 结束日期
        self.iv_history_end_date = TgDateEdit()
        controls_layout.addWidget(self.iv_history_end_date)
        
        # 查询按钮
        self.query_iv_history_button = TgButton("查询")
        controls_layout.addWidget(self.query_iv_history_button)
        
        controls_layout.addStretch(1)
        return controls_layout

    def _create_iv_surface_3d_section(self):
        """创建3D波动率曲面图表区域"""
        # 创建控件
        controls_layout = self._create_iv_surface_3d_controls()
        self.scroll_layout.addLayout(controls_layout)

        # 添加说明标签
        surface_explanation_label = TgLabel("每个到期日、每个行权价的隐含波动率曲面", style_type='description')
        surface_explanation_label.setWordWrap(True)
        self.scroll_layout.addWidget(surface_explanation_label)

        # 创建3D图表
        self.iv_surface_3d_chart = TgSurface3DChart()
        self.iv_surface_3d_chart.setMinimumHeight(550)
        self.iv_surface_3d_chart.setMinimumWidth(600)
        self.iv_surface_3d_chart.set_title("期权隐含波动率3D曲面")
        self.scroll_layout.addWidget(self.iv_surface_3d_chart)
        self.scroll_layout.addSpacing(20)

    def _create_iv_surface_3d_controls(self):
        """创建3D波动率曲面控件"""
        controls_layout = TgHBoxLayout()
        
        # 日期选择
        controls_layout.addWidget(TgLabel("日期:"))
        self.iv_surface_date_input = TgDateEdit()
        controls_layout.addWidget(self.iv_surface_date_input)
        
        # 标的选择
        controls_layout.addWidget(TgLabel("标的:"))
        self.iv_surface_underlying_combo = TgComboBox()
        self.iv_surface_underlying_combo.setMinimumWidth(120)
        self.iv_surface_underlying_combo.setMaximumWidth(200)
        controls_layout.addWidget(self.iv_surface_underlying_combo)
        
        # 期权类型选择
        controls_layout.addWidget(TgLabel("期权类型:"))
        self.iv_surface_option_class_combo = TgComboBox()
        self.iv_surface_option_class_combo.addItem("CALL", "CALL")
        self.iv_surface_option_class_combo.addItem("PUT", "PUT")
        self.iv_surface_option_class_combo.setMinimumWidth(80)
        self.iv_surface_option_class_combo.setMaximumWidth(100)
        controls_layout.addWidget(self.iv_surface_option_class_combo)
        
        # 查询按钮
        self.query_iv_surface_button = TgButton("查询iv曲面")
        controls_layout.addWidget(self.query_iv_surface_button)
        
        controls_layout.addStretch(1)
        return controls_layout

    def setup_underlying_symbols(self, symbols: Dict[str, str]):
        """设置标的符号下拉框"""
        # 保留波动率锥查询的控件
        self.underlying_combo.clear()
        self.historical_iv_underlying_combo.clear()
        self.iv_history_underlying_combo.clear()
        self.iv_surface_underlying_combo.clear()
        for code, name in symbols.items():
            item_text = f"{name} ({code})"
            self.underlying_combo.addItem(item_text, code)
            self.historical_iv_underlying_combo.addItem(item_text, code)
            self.iv_history_underlying_combo.addItem(item_text, code)
            self.iv_surface_underlying_combo.addItem(item_text, code)
        
        # 同步所有下拉框的选择
        self.underlying_combo.currentIndexChanged.connect(self.historical_iv_underlying_combo.setCurrentIndex)
        self.underlying_combo.currentIndexChanged.connect(self.iv_history_underlying_combo.setCurrentIndex)
        self.underlying_combo.currentIndexChanged.connect(self.iv_surface_underlying_combo.setCurrentIndex)
        self.historical_iv_underlying_combo.currentIndexChanged.connect(self.underlying_combo.setCurrentIndex)
        self.historical_iv_underlying_combo.currentIndexChanged.connect(self.iv_history_underlying_combo.setCurrentIndex)
        self.historical_iv_underlying_combo.currentIndexChanged.connect(self.iv_surface_underlying_combo.setCurrentIndex)
        self.iv_history_underlying_combo.currentIndexChanged.connect(self.underlying_combo.setCurrentIndex)
        self.iv_history_underlying_combo.currentIndexChanged.connect(self.historical_iv_underlying_combo.setCurrentIndex)
        self.iv_history_underlying_combo.currentIndexChanged.connect(self.iv_surface_underlying_combo.setCurrentIndex)
        self.iv_surface_underlying_combo.currentIndexChanged.connect(self.underlying_combo.setCurrentIndex)
        self.iv_surface_underlying_combo.currentIndexChanged.connect(self.historical_iv_underlying_combo.setCurrentIndex)
        self.iv_surface_underlying_combo.currentIndexChanged.connect(self.iv_history_underlying_combo.setCurrentIndex)

    def set_default_date(self, date_str: str):
        """设置默认日期"""
        # 获取最近一个交易日作为默认日期
        latest_trading_date = get_latest_trading_date()
        if latest_trading_date:
            date = datetime.strptime(latest_trading_date, '%Y-%m-%d').date()
            logger.info(f"使用最近交易日作为默认日期: {latest_trading_date}")
        else:
            # 如果获取失败，使用传入的日期
            date = datetime.strptime(date_str, '%Y-%m-%d').date()
            logger.warning(f"获取最近交易日失败，使用默认日期: {date_str}")
        
        # 保留波动率锥查询的日期输入控件
        self.date_input.set_python_date(date)
        
        # 设置历史IV查询的默认日期范围
        end_date = date
        start_date = end_date - timedelta(days=360)
        self.start_date_input.set_python_date(start_date)
        self.end_date_input.set_python_date(end_date)
        
        # 设置IV历史查询的默认日期范围
        self.iv_history_start_date.set_python_date(start_date)
        self.iv_history_end_date.set_python_date(end_date)
        
        # 设置3D波动率曲面的默认日期
        self.iv_surface_date_input.set_python_date(date)

    def get_query_params(self):
        """获取波动率锥查询参数"""
        target_date = self.date_input.get_date_string("yyyy-MM-dd")
        underlying_symbol = self.underlying_combo.currentData()
        return underlying_symbol, target_date

    def get_historical_iv_query_params(self):
        """获取历史IV查询参数"""
        start_date = self.start_date_input.get_date_string("yyyy-MM-dd")
        end_date = self.end_date_input.get_date_string("yyyy-MM-dd")
        underlying_symbol = self.historical_iv_underlying_combo.currentData()
        option_class = self.historical_iv_option_class_combo.currentData()
        return underlying_symbol, start_date, end_date, option_class

    def get_iv_history_query_params(self):
        """获取IV历史查询参数"""
        start_date = self.iv_history_start_date.get_date_string("yyyy-MM-dd")
        end_date = self.iv_history_end_date.get_date_string("yyyy-MM-dd")
        underlying_symbol = self.iv_history_underlying_combo.currentData()
        return underlying_symbol, start_date, end_date

    def get_iv_surface_query_params(self):
        """获取3D波动率曲面查询参数"""
        date = self.iv_surface_date_input.get_date_string("yyyy-MM-dd")
        underlying_symbol = self.iv_surface_underlying_combo.currentData()
        option_class = self.iv_surface_option_class_combo.currentData()
        return underlying_symbol, date, option_class

    # 波动率偏斜查询加载状态设置方法 - 已注释
    # def set_query_loading(self, is_loading: bool):
    #     self.query_button.setEnabled(not is_loading)
    #     self.query_button.setText("查询中..." if is_loading else "查询偏斜")

    def set_historical_iv_query_loading(self, is_loading: bool):
        self.query_historical_iv_button.setEnabled(not is_loading)
        self.query_historical_iv_button.setText("查询中..." if is_loading else "查询")

    def set_iv_history_query_loading(self, is_loading: bool):
        self.query_iv_history_button.setEnabled(not is_loading)
        self.query_iv_history_button.setText("查询中..." if is_loading else "查询")

    def set_iv_surface_query_loading(self, is_loading: bool):
        self.query_iv_surface_button.setEnabled(not is_loading)
        self.query_iv_surface_button.setText("查询中..." if is_loading else "查询iv曲面")

    def update_historical_iv_chart(self, historical_data: Dict):
        """更新历史隐含波动率图表"""
        try:
            self.historical_iv_chart.clear()
            
            if not historical_data:
                logger.warning("没有历史隐含波动率数据可显示")
                return

            colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd',
                      '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']
            color_index = 0
            valid_data_found = False

            for expiry_date, data_points in historical_data.items():
                if not data_points:
                    continue

                sorted_points = sorted(data_points, key=lambda x: x['date'])
                
                dates = [datetime.strptime(p['date'], '%Y-%m-%d').timestamp() for p in sorted_points]
                ivs = [p['atm_iv'] for p in sorted_points]

                if not dates or not ivs:
                    continue

                self.historical_iv_chart.add_line_chart(
                    x=dates,
                    y=ivs,
                    name=f"到期日: {expiry_date}",
                    color=colors[color_index % len(colors)]
                )
                color_index += 1
                valid_data_found = True

            if not valid_data_found:
                logger.warning("没有找到有效的历史IV数据")
                return

            self.historical_iv_chart.plot_widget.setLabel('left', '平值隐含波动率 (ATM IV)')
            self.historical_iv_chart.plot_widget.setLabel('bottom', '日期')
            self.historical_iv_chart.auto_range()
            logger.info("历史隐含波动率图表绘制完成")

        except Exception as e:
            logger.error(f"绘制历史隐含波动率图表时出错: {e}")
            self.historical_iv_chart.clear()

    # 波动率偏斜曲线更新方法 - 已注释
    # def update_volatility_skew(self, skew_data: Dict):
    #     """更新波动率偏斜曲线"""
    #     try:
    #         # 清空图表
    #         self.volatility_chart.clear()
    #         
    #         # 检查是否有有效数据
    #         if not skew_data:
    #             logger.warning("没有波动率偏斜数据可显示")
    #             return
    #         
    #         # 定义颜色列表
    #         colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', 
    #                  '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']
    #         
    #         # 为每个到期日绘制一条线
    #         color_index = 0
    #         valid_data_found = False
    #         
    #         for expiry_date, data_points in skew_data.items():
    #             if not data_points:
    #                 logger.debug(f"到期日 {expiry_date} 没有数据点")
    #                 continue
    #                 
    #             # 按行权价排序
    #             sorted_points = sorted(data_points, key=lambda x: float(x.get('strike_price', 0)))
    #             
    #             # 提取数据并确保数据类型正确
    #             strike_prices = []
    #             ivs = []
    #             
    #             for point in sorted_points:
    #                 try:
    #                     strike = float(point.get('strike_price', 0))
    #                     iv = float(point.get('iv', 0))
    #                     if strike > 0 and iv > 0:  # 确保数据有效
    #                         strike_prices.append(strike)
    #                         ivs.append(iv)
    #                 except (ValueError, TypeError) as e:
    #                     logger.debug(f"跳过无效数据点: {point}, 错误: {e}")
    #                     continue
    #             
    #             if not strike_prices or not ivs:
    #                 logger.debug(f"到期日 {expiry_date} 没有有效数据点")
    #                 continue
    #                 
    #             logger.info(f"绘制到期日 {expiry_date}, 数据点数: {len(strike_prices)}, 行权价范围: {min(strike_prices)}-{max(strike_prices)}, IV范围: {min(ivs):.4f}-{max(ivs):.4f}")
    #             
    #             # 绘制线条
    #             self.volatility_chart.add_line_chart(
    #                 x=strike_prices,
    #                 y=ivs,
    #                 name=f"到期日: {expiry_date}",
    #                 color=colors[color_index % len(colors)]
    #             )
    #             
    #             color_index += 1
    #             valid_data_found = True
    #         
    #         if not valid_data_found:
    #             logger.warning("没有找到有效的波动率偏斜数据")
    #             return
    #         
    #         # 设置坐标轴标签
    #         self.volatility_chart.plot_widget.setLabel('left', '隐含波动率 (IV)')
    #         self.volatility_chart.plot_widget.setLabel('bottom', '行权价 (Strike Price)')
    #         
    #         # 强制显示坐标轴
    #         self.volatility_chart.plot_widget.showAxis('bottom', True)
    #         self.volatility_chart.plot_widget.showAxis('left', True)
    #         
    #         # 自动调整范围
    #         self.volatility_chart.auto_range()
    #         
    #         # 针对期权数据的特定调整
    #         self._adjust_chart_for_options_data()
    #         
    #         logger.info("波动率偏斜曲线绘制完成")
    #         
    #     except Exception as e:
    #         logger.error(f"绘制波动率偏斜曲线时出错: {e}")
    #         self.volatility_chart.clear()

    # 波动率偏斜图表调整方法 - 已注释
    # def _adjust_chart_for_options_data(self):
    #     """针对期权数据调整图表显示"""
    #     try:
    #         vb = self.volatility_chart.plot_widget.getViewBox()
    #         current_range = vb.viewRange()
    #         
    #         # 获取当前数据范围
    #         x_range = current_range[0]
    #         y_range = current_range[1]
    #         
    #         # 确保y轴（隐含波动率）不小于0
    #         y_min = max(0, y_range[0])
    #         y_max = y_range[1]
    #         
    #         # 为x轴（行权价）添加更多边距，确保完整显示
    #         x_span = x_range[1] - x_range[0]
    #         x_padding = max(x_span * 0.05, 50)  # 至少50个单位的边距
    #         
    #         x_min = x_range[0] - x_padding
    #         x_max = x_range[1] + x_padding
    #         
    #         # 重新设置范围
    #         vb.setRange(
    #             xRange=[x_min, x_max],
    #             yRange=[y_min, y_max],
    #             padding=0
    #         )
    #         
    #     except Exception as e:
    #         logger.debug(f"调整图表范围时出错: {e}")

    def update_cone_chart(self, cone_data: Dict):
        """更新波动率锥曲线"""
        try:
            self.cone_chart.clear()
            
            if not cone_data:
                logger.warning("没有波动率锥数据可显示")
                return

            call_data = cone_data.get('call', {})
            put_data = cone_data.get('put', {})
            
            if not call_data and not put_data:
                logger.warning("没有有效的波动率锥数据")
                return

            # 定义颜色
            call_color = '#1f77b4'  # 蓝色
            put_color = '#ff7f0e'   # 橙色

            # 合并所有到期日并排序，确保CALL和PUT使用相同的x轴
            all_dates = set()
            if call_data:
                all_dates.update(call_data.keys())
            if put_data:
                all_dates.update(put_data.keys())
            
            sorted_dates = sorted(all_dates)
            
            # 为每个日期创建对应的时间戳作为x轴值
            x_values = []
            for date_str in sorted_dates:
                try:
                    date_obj = datetime.strptime(date_str, '%Y-%m-%d')
                    x_values.append(date_obj.timestamp())
                except ValueError:
                    logger.warning(f"无效的日期格式: {date_str}")
                    continue

            # 绘制CALL曲线
            if call_data and x_values:
                call_ivs = []
                call_x_vals = []
                
                for i, date_str in enumerate(sorted_dates):
                    if date_str in call_data and call_data[date_str] is not None:
                        try:
                            iv_value = float(call_data[date_str])
                            call_ivs.append(iv_value)
                            call_x_vals.append(x_values[i])
                        except (ValueError, TypeError):
                            continue
                
                if call_x_vals and call_ivs:
                    self.cone_chart.add_line_chart(
                        x=call_x_vals,
                        y=call_ivs,
                        name="CALL",
                        color=call_color
                    )

            # 绘制PUT曲线
            if put_data and x_values:
                put_ivs = []
                put_x_vals = []
                
                for i, date_str in enumerate(sorted_dates):
                    if date_str in put_data and put_data[date_str] is not None:
                        try:
                            iv_value = float(put_data[date_str])
                            put_ivs.append(iv_value)
                            put_x_vals.append(x_values[i])
                        except (ValueError, TypeError):
                            continue
                
                if put_x_vals and put_ivs:
                    self.cone_chart.add_line_chart(
                        x=put_x_vals,
                        y=put_ivs,
                        name="PUT",
                        color=put_color
                    )

            # 设置坐标轴标签
            self.cone_chart.plot_widget.setLabel('left', '隐含波动率 (IV)')
            self.cone_chart.plot_widget.setLabel('bottom', '到期日')
            
            # 自动调整范围
            self.cone_chart.auto_range()
            
            logger.info("波动率锥曲线绘制完成")
            
        except Exception as e:
            logger.error(f"绘制波动率锥曲线时出错: {e}")
            self.cone_chart.clear()

    def update_cone_chart_with_previous(self, combined_data: Dict):
        """更新波动率锥曲线（包含当前和前一交易日数据）"""
        try:
            self.cone_chart.clear()
            
            if not combined_data:
                logger.warning("没有锥曲线组合数据可显示")
                return

            current_data = combined_data.get('current', {}).get('data', {})
            previous_data = combined_data.get('previous', {}).get('data', {})
            current_date = combined_data.get('current', {}).get('date', '')
            previous_date = combined_data.get('previous', {}).get('date', '')
            
            if not current_data and not previous_data:
                logger.warning("没有有效的锥曲线数据")
                return

            # 定义颜色：当前日期用深色，前一日期用浅色
            current_call_color = '#1f77b4'  # 深蓝色
            current_put_color = '#ff7f0e'   # 深橙色
            previous_call_color = '#87ceeb'  # 浅蓝色
            previous_put_color = '#ffa500'   # 浅橙色

            # 只使用当前日期有数据的到期日作为X轴基准
            current_dates = set()
            if current_data:
                call_data = current_data.get('call', {})
                put_data = current_data.get('put', {})
                if call_data:
                    current_dates.update(call_data.keys())
                if put_data:
                    current_dates.update(put_data.keys())
            
            if not current_dates:
                logger.warning("当前日期没有波动率锥数据")
                return
                
            sorted_dates = sorted(current_dates)
            logger.info(f"波动率锥曲线基于当前日期到期日: {sorted_dates}")
            
            # 为当前日期的每个到期日创建时间戳映射
            date_to_timestamp = {}
            for date_str in sorted_dates:
                try:
                    date_obj = datetime.strptime(date_str, '%Y-%m-%d')
                    date_to_timestamp[date_str] = date_obj.timestamp()
                except ValueError:
                    logger.warning(f"无效的日期格式: {date_str}")
                    continue

            # 绘制当前日期的CALL曲线（实线）
            if current_data and date_to_timestamp:
                call_data = current_data.get('call', {})
                if call_data:
                    call_ivs = []
                    call_x_vals = []
                    
                    for date_str in sorted_dates:
                        if date_str in call_data and call_data[date_str] is not None and date_str in date_to_timestamp:
                            try:
                                iv_value = float(call_data[date_str])
                                call_ivs.append(iv_value)
                                call_x_vals.append(date_to_timestamp[date_str])
                            except (ValueError, TypeError):
                                continue
                    
                    if call_x_vals and call_ivs:
                        self.cone_chart.add_line_chart(
                            x=call_x_vals,
                            y=call_ivs,
                            name=f"CALL - 当前 ({current_date})",
                            color=current_call_color
                        )
                        logger.info(f"绘制当前CALL曲线，{len(call_x_vals)}个数据点")

            # 绘制当前日期的PUT曲线（实线）
            if current_data and date_to_timestamp:
                put_data = current_data.get('put', {})
                if put_data:
                    put_ivs = []
                    put_x_vals = []
                    
                    for date_str in sorted_dates:
                        if date_str in put_data and put_data[date_str] is not None and date_str in date_to_timestamp:
                            try:
                                iv_value = float(put_data[date_str])
                                put_ivs.append(iv_value)
                                put_x_vals.append(date_to_timestamp[date_str])
                            except (ValueError, TypeError):
                                continue
                    
                    if put_x_vals and put_ivs:
                        self.cone_chart.add_line_chart(
                            x=put_x_vals,
                            y=put_ivs,
                            name=f"PUT - 当前 ({current_date})",
                            color=current_put_color
                        )
                        logger.info(f"绘制当前PUT曲线，{len(put_x_vals)}个数据点")

            # 绘制前一交易日的CALL曲线（只绘制当前日期也有的到期日）
            if previous_data and previous_date and date_to_timestamp:
                prev_call_data = previous_data.get('call', {})
                if prev_call_data:
                    prev_call_ivs = []
                    prev_call_x_vals = []
                    
                    # 只遍历当前日期有数据的到期日
                    for date_str in sorted_dates:
                        if (date_str in prev_call_data and 
                            prev_call_data[date_str] is not None and 
                            date_str in date_to_timestamp):
                            try:
                                iv_value = float(prev_call_data[date_str])
                                prev_call_ivs.append(iv_value)
                                prev_call_x_vals.append(date_to_timestamp[date_str])
                            except (ValueError, TypeError):
                                continue
                    
                    if prev_call_x_vals and prev_call_ivs:
                        self.cone_chart.add_line_chart(
                            x=prev_call_x_vals,
                            y=prev_call_ivs,
                            name=f"CALL - 前日 ({previous_date})",
                            color=previous_call_color,
                            style='dash'
                        )
                        logger.info(f"绘制前日CALL曲线，{len(prev_call_x_vals)}个数据点（基于当前日期到期日）")

            # 绘制前一交易日的PUT曲线（只绘制当前日期也有的到期日）
            if previous_data and previous_date and date_to_timestamp:
                prev_put_data = previous_data.get('put', {})
                if prev_put_data:
                    prev_put_ivs = []
                    prev_put_x_vals = []
                    
                    # 只遍历当前日期有数据的到期日
                    for date_str in sorted_dates:
                        if (date_str in prev_put_data and 
                            prev_put_data[date_str] is not None and 
                            date_str in date_to_timestamp):
                            try:
                                iv_value = float(prev_put_data[date_str])
                                prev_put_ivs.append(iv_value)
                                prev_put_x_vals.append(date_to_timestamp[date_str])
                            except (ValueError, TypeError):
                                continue
                    
                    if prev_put_x_vals and prev_put_ivs:
                        self.cone_chart.add_line_chart(
                            x=prev_put_x_vals,
                            y=prev_put_ivs,
                            name=f"PUT - 前日 ({previous_date})",
                            color=previous_put_color,
                            style='dash'
                        )
                        logger.info(f"绘制前日PUT曲线，{len(prev_put_x_vals)}个数据点（基于当前日期到期日）")

            # 设置坐标轴标签
            self.cone_chart.plot_widget.setLabel('left', '隐含波动率 (IV)')
            self.cone_chart.plot_widget.setLabel('bottom', '到期日')
            
            # 自动调整范围
            self.cone_chart.auto_range()
            
            # 统计绘制的曲线数量
            curves_drawn = 0
            if current_data.get('call'): curves_drawn += 1
            if current_data.get('put'): curves_drawn += 1
            if previous_data.get('call'): curves_drawn += 1
            if previous_data.get('put'): curves_drawn += 1
            
            logger.info(f"波动率锥曲线（含前一交易日）绘制完成，共绘制 {curves_drawn} 条曲线")
            
        except Exception as e:
            logger.error(f"绘制波动率锥曲线（含前一交易日）时出错: {e}")
            self.cone_chart.clear()

    def update_iv_history_chart(self, iv_history_data: list):
        """更新IV历史折线图，显示4条曲线：CALL/PUT × 近月/远月"""
        try:
            self.iv_history_chart.clear()
            
            if not iv_history_data:
                logger.warning("没有IV历史数据可显示")
                return

            # 按类型和近月标志分组数据
            data_groups = {
                'CALL_nearby': [],
                'CALL_distant': [],
                'PUT_nearby': [],
                'PUT_distant': []
            }
            
            for item in iv_history_data:
                option_class = item.get('option_class', '').upper()
                is_nearby = item.get('is_nearby_month', False)
                
                if option_class == 'CALL':
                    group_key = 'CALL_nearby' if is_nearby else 'CALL_distant'
                elif option_class == 'PUT':
                    group_key = 'PUT_nearby' if is_nearby else 'PUT_distant'
                else:
                    continue
                    
                data_groups[group_key].append(item)

            # 定义颜色和线条样式
            curve_configs = {
                'CALL_nearby': {'color': '#1f77b4', 'name': 'CALL 近月'},
                'CALL_distant': {'color': '#ff7f0e', 'name': 'CALL 远月'},
                'PUT_nearby': {'color': '#2ca02c', 'name': 'PUT 近月'},
                'PUT_distant': {'color': '#d62728', 'name': 'PUT 远月'}
            }

            valid_data_found = False

            # 为每个组绘制曲线
            for group_key, data_points in data_groups.items():
                if not data_points:
                    continue

                # 按日期排序
                sorted_points = sorted(data_points, key=lambda x: x['date'])
                
                # 提取时间和IV数据
                dates = []
                ivs = []
                
                for point in sorted_points:
                    try:
                        date_obj = datetime.strptime(point['date'], '%Y-%m-%d')
                        iv_value = float(point.get('iv', 0))
                        
                        if iv_value > 0:  # 确保IV数据有效
                            dates.append(date_obj.timestamp())
                            ivs.append(iv_value)
                    except (ValueError, TypeError) as e:
                        logger.debug(f"跳过无效数据点: {point}, 错误: {e}")
                        continue

                if not dates or not ivs:
                    continue

                # 绘制曲线
                config = curve_configs[group_key]
                self.iv_history_chart.add_line_chart(
                    x=dates,
                    y=ivs,
                    name=config['name'],
                    color=config['color']
                )
                
                valid_data_found = True
                logger.info(f"绘制{config['name']}曲线，数据点数: {len(dates)}")

            if not valid_data_found:
                logger.warning("没有找到有效的IV历史数据")
                return

            # 设置坐标轴标签
            self.iv_history_chart.plot_widget.setLabel('left', '隐含波动率 (IV)')
            self.iv_history_chart.plot_widget.setLabel('bottom', '日期')
            
            # 自动调整范围
            self.iv_history_chart.auto_range()
            
            logger.info("IV历史折线图绘制完成")

        except Exception as e:
            logger.error(f"绘制IV历史折线图时出错: {e}")
            self.iv_history_chart.clear()

    def update_iv_surface_3d_chart(self, surface_data: list):
        """更新3D波动率曲面图表"""
        try:
            if not surface_data:
                logger.warning("没有3D波动率曲面数据可显示")
                return

            # 将数据转换为DataFrame
            df = pd.DataFrame(surface_data)
            
            if df.empty:
                logger.warning("3D波动率曲面数据为空")
                return

            # 验证必需的列是否存在
            required_columns = ['expire_date', 'strike_price', 'iv']
            missing_columns = [col for col in required_columns if col not in df.columns]
            if missing_columns:
                logger.error(f"3D波动率曲面数据缺少必需列: {missing_columns}")
                return

            # 过滤有效数据（iv > 0）
            df = df[df['iv'] > 0].copy()
            
            if df.empty:
                logger.warning("过滤后的3D波动率曲面数据为空（所有iv值都 <= 0）")
                return

            # 将到期日转换为距离当前日期的天数，用作X轴
            current_date = df.iloc[0].get('date', pd.Timestamp.now().strftime('%Y-%m-%d'))
            current_date = pd.to_datetime(current_date)
            
            df['expire_date'] = pd.to_datetime(df['expire_date'])
            df['days_to_expiry'] = (df['expire_date'] - current_date).dt.days
            
            # 过滤掉已过期的期权（天数为负）
            df = df[df['days_to_expiry'] >= 0].copy()
            
            if df.empty:
                logger.warning("过滤后没有有效的未到期期权数据")
                return

            # 设置图表数据：X轴=到期天数，Y轴=行权价，Z轴=隐含波动率
            self.iv_surface_3d_chart.set_data(df, 'days_to_expiry', 'strike_price', 'iv')
            
            # 设置图表标题和颜色
            option_class = df.iloc[0].get('option_class', 'UNKNOWN')
            underlying = df.iloc[0].get('underlying_symbol', 'UNKNOWN')
            date_str = current_date.strftime('%Y-%m-%d')
            
            title = f"{underlying} {option_class}期权隐含波动率3D曲面 ({date_str})"
            self.iv_surface_3d_chart.set_title(title)
            self.iv_surface_3d_chart.set_color_map('viridis')  # 使用viridis配色方案
            
            logger.info(f"3D波动率曲面图表更新成功，数据点数: {len(df)}")
            logger.info(f"到期天数范围: {df['days_to_expiry'].min()}-{df['days_to_expiry'].max()}天")
            logger.info(f"行权价范围: {df['strike_price'].min():.2f}-{df['strike_price'].max():.2f}")
            logger.info(f"隐含波动率范围: {df['iv'].min():.4f}-{df['iv'].max():.4f}")

        except Exception as e:
            logger.error(f"更新3D波动率曲面图表时出错: {e}")
            if hasattr(self, 'iv_surface_3d_chart'):
                self.iv_surface_3d_chart.clear()  # 清空图表

    def clear_charts(self):
        """清理图表"""
        # 波动率偏斜图表已注释，跳过清理
        # if hasattr(self, 'volatility_chart'):
        #     self.volatility_chart.clear()
        if hasattr(self, 'cone_chart'):
            self.cone_chart.clear()
        if hasattr(self, 'historical_iv_chart'):
            self.historical_iv_chart.clear()
        if hasattr(self, 'iv_history_chart'):
            self.iv_history_chart.clear()
        if hasattr(self, 'iv_surface_3d_chart'):
            # 清空3D曲面图表
            self.iv_surface_3d_chart.clear()